#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ReadFile.h"
#include "LRU.h"

#define SEC_PRE_PAGE 4
#define MAX_BUF_SIZE 1000
int main()
{
    /*关于文件读取操作的变量*/
    UINT8  szFileName[256] = {0};     // 包含完整路径的文件名
    FILE  *fp= NULL;    // 文件句柄
    UINT8  szRecordSet[MAX_RECORD_LEN] = {0};   // 存放从文件中读取到的记录内容集
    UINT8  szRecordInfo[MAX_RECORD_LEN] = {0};   // 存放从文件中读取到的每条记录内容
    int iRetVal=0;
    //关于trace的文件变量
    double time;
    int devno,blkno,bcount,Opera_flag,secno,scount;
    /**************************************/
    /*链表操作的变量定义*/
    BufList Head;
    int Buf_length=0;
    InitBufList(&Head);
    int Max_length=MAX_BUF_SIZE;
    Buf_length=BufListLength(Head);
    /**************************************/
    /*定义统计变量*/
    int write_back_count=0;
    int physical_write_count=0;
    int physical_read_count=0;
    int all_req_count=0;
    int read_miss_count=0;
    int write_miss_count=0;
    int read_hit_count=0;
    int write_hit_count=0;
    int evict_count=0;
    /**************************************/
//  test point
//    printf("the Buf_length is %d\n",Buf_length);


    // 获取包含完整路径的文件名
    //szFileName是打开的文件绝对路径
    //strcpy(szFileName, "/home/zxin10/zhouzx/test/file/TestFile.txt");
    //自定义加入文件的路径
    printf("Input trace file path\n");
   //gets函数可能出现输入越界,所以改用fgets函数
    //gets(szFileName);
    fgets(szFileName,256,stdin);
    //处理掉输入的换行符
    int L=strlen(szFileName);
    if (L>0)
    {
        if (szFileName[L-1]=='\n' || szFileName[L-1]=='\t')
            {
                szFileName[L-1]='\0';
            }
            L--;
    }
    // 打开文件
    fp = fopen(szFileName, "r");
    if (NULL == fp)   // 打开失败
    {
        printf("Open file %s failed!\n", szFileName);
        return -1;
    }else
    {
        printf("Open file %s success!\n",szFileName);
    }
    //test point

    //加入对缓冲区链表的初始化操作

    while (1)
    {
        //利用函数memset快速置位
        memset(szRecordSet, 0x00, sizeof(szRecordSet));

        iRetVal = ReadRecordFromFile(fp, szRecordSet);
        if (iRetVal == -1)   // 表示函数执行失败, 直接退出
        {
            printf("Exec ReadRecordFromFile failed, please check!\n");
            break;
        }
        else if (iRetVal == 1)
        {
            printf("the file %s read finished\n",szFileName);
            break;
        }else
        {
            //打印输出读取到的记录值
            memset(szRecordInfo,0x00,sizeof(szRecordInfo));
            strncpy(szRecordInfo, szRecordSet, sizeof(szRecordInfo)-1);
            //开始操作处理数据
            if (sscanf(szRecordInfo, "%lf %d %d %d %d\n", &time, &devno, &secno, &scount, &Opera_flag) == 0)
            {
                fprintf(stderr, "Wrong number of arguments for I/O trace event type\n");
                fprintf(stderr, "szRecordInfo: %s", szRecordInfo);
                break;
            }
//            printf("the requst sec number is %d\n",blkno);
//            printf("%s\n", szRecordInfo);
//         这里开始穿插对缓冲区算法的研究仿真代码
//         扇区请求进行对齐处理
            blkno=secno/SEC_PRE_PAGE;
            bcount=(secno+scount-1)/SEC_PRE_PAGE-(secno)/SEC_PRE_PAGE+1;
            int curr_req_cnt=bcount;
            int curr_LPN=blkno;
//          测试输出语句
            printf("the blkno is %d\t the bcount is %d\n",blkno,bcount);

            //单个大小为bcount的请求处理
            while(curr_req_cnt>0)
            {
//               首先遍历缓冲区，是否命中该curr_LPN
                BufList P_index=FindLPN(Head,curr_LPN);
                if(P_index!=NULL)
                {/*命中buf*/
                    //判断命中的读写类型
                    if(Opera_flag)
                    {
                        read_hit_count++;
                    }else
                    {
                        write_hit_count++;
                        P_index->isD=Opera_flag;
                    }
                    //将命中的LPN移动置MRU位置
                    MoveToMRU(Head,P_index);
                }
                else
                {//未命中buf，则加载进入缓冲区
                    //判断未命中的读写类型
                    if(Opera_flag)
                    {
                        read_miss_count++;
                    }else
                    {
                        write_miss_count++;
                    }
                    //判断缓冲是否满
                    if(IsFull(Head,Max_length))
                    {
                        //执行剔除操作
                        evict_count++;
//                        DeleteLRU(Head);
                        if(!DeleteLRU(Head))
                        {
                            //删除的是脏页
                            write_back_count++;
                            physical_write_count++;
                        }
                    }
                    //将该请求加入队列
                    AddNewToMRU(Head,curr_LPN,Opera_flag);
                    physical_read_count++;
                }

                curr_req_cnt--;
                curr_LPN++;
            }
        }
    }

    all_req_count=read_hit_count+read_miss_count+write_miss_count+write_hit_count;
    //结束注意释放链表空间
    DestroyBufList(&Head);
    //输出统计的结果：
    printf("the physical_read_count is %d\t the physical_write_count is %d\n",physical_read_count,physical_write_count);
    printf("the all_req_count is %d\n",all_req_count);
    printf("the hit rate count is %lf\n", (double)(read_hit_count+write_hit_count)/all_req_count);
    //............
    return 0;
}

